var LNResponse=require('./Response').LNResponse;
var fs=require('fs');
var http=require("http");

function prepare_ajajform_iframe(data)
{
	if (data===undefined || data===null) return "undefined";
	if (data.toString().match(/^[^\d\{\"]/)) return JSON.stringify(data);
	return data;
}

/**
 * Class: LNTimedRun
 */
function LNTimedRun()
{
}

LNTimedRun.prototype.init=function()
{
	this.stats={};
}

LNTimedRun.prototype.add=function(name,d1)
{
	var d2=new Date();
	var dd=d2-d1;
	if (this.stats[name]) this.stats[name]+=dd; else this.stats[name]=dd;
}

LNTimedRun.prototype.send=function(url,sitename,action_src,action)
{
	var args="";
	for (var k in this.stats) args+="&"+k+"="+this.stats[k];
	var request=new ClientRequest(url+"?__site="+sitename+"&__url="+encodeURIComponent(action)+"&__url_src="+encodeURIComponent(action_src)+args);
	request.send();
}

/**
 * Class: LNRR
 *		Request-response class
 *
 * Properties:
 *		action typeof String				- request URI, stripped of parameters, i.e. '/mypage/'
 *		action_src typeof String			- original request URI, since action is subject to rewrite
 *		fields typeof HttpFields			- request parameters hash, i.e. ?a=b&c=d&c=e mapped to {a:"b",c:["d","e"]}
 *		jsng_response typeof LNResponse	- 
 *		res typeof HttpResponse				-
 *		req typeof HttpRequest				-
 *		role_ids typeof Object				- map of user role ids or empty object, i.e. { "1":1,"7":1}
 *		roles typeof Object					- map of user role codes or empty object, i.e. { admin:1, edit_news: 1}
 *		server_domain typeof String			- server domain, i.e. "mysite.com"
 *		server_name typeof String			- server name, i.e. "www.mysite.com"
 *		site typeof SiteObject				- site object
 *		uid typeof Integer					- user id from Tusers or 0
 *		urlprefix typeof String				- url prefix, i.e. "" or "/ru"
 *		user typeof User/Model				- user model or an empty object
 *		v8iteration typeof Integer			- iteration number of LNServer (if in FASTCGI mode)
 */

/**
 * Method: Constructor
 *
 * Parameters:
 *		req typeof HttpRequest - current http request
 *		resp typeof HttpResponse - wannabe http response
 *		server typeof LNServer - server instance
 *
 * Returns:
 */
function LNRR(req,resp,server)
{
	var req_uri=system.env.REQUEST_URI || req.uri || "/";
	this._cache={};
	this.prototype=this;
	this.auth_engine=server.auth_engine;
	this.v8iteration=server.iterations;
	this.req=req;
	this.res=resp;
	this.fields=req[req.method.toLowerCase()];
	this.ln_response=this.jsng_response=new LNResponse(resp);
	this.uid=0;
	this.roles={};
	this.role_ids={};
	this.user={};
	this.action=req_uri.match(/^([^?]*)/)[1];
	this.Dumper=server.Dumper;
	this.SafeDumper=server.SafeDumper;
	this.server_name=system.env.SERVER_NAME||req.server_name;
	this.system=server.options.system;
	if (!this.action.match(/\/$/)) {
		this.action+="/";
		this.missed_slash = true;
	}
	/*,
		controllers: this.options.system.refs.controllers,
		models: this.options.system.refs.models,
		functions: this.options.system.refs.functions,
		views: this.views,
		system: this.options.system,
		site_option: site_option,
		owsessions:owsessions*/
	this.server_domain=this.server_name.match(/^([\w\-]+)\.(.+)$/)[2];
	if (!this.fields) this.fields={};
	this.action_src=this.action;
	return this;
}

/**
 * Method: set_site
 *
 * Parameters:
 *		site typeof SiteObject - site object
 */
LNRR.prototype.set_site=function(site)
{
	this.site=site;
	this.use_l10n_id=this.site.default_l10n_id;
	this.fallback_l10n_id=this.site.fallback_l10n_id;
	if (this.site.urlprefix && !("urlprefix" in this)) this.urlprefix=this.site.urlprefix;
	if (site.timed_run) {
		this.timed_run=new LNTimedRun();
		this.timed_run.init();
	}
}

/**
 * Method: do_rewrites
 *		Does rewrites
 *
 * Parameters:
 *
 * Returns:
 */
LNRR.prototype.do_rewrites=function()
{
	if (this.fields.set_medium_preference) {
		var exp=new Date(new Date().getTime() + 1000*24*60*60*1000);
		this.res.cookie("medium_preference",this.fields.set_medium_preference,exp,'/',this.site.cookie_domain);
		this.req.cookie.medium_preference=this.fields.set_medium_preference;
	}

	if (this.action=="/") {
		var mp=this.req.cookie.medium_preference;
		switch (mp) {
			case "mobile":
				this.action="/mobile/index/";
				break;
			case "desktop":
				this.action="/index/";
				break;
			default:	
				if (this.site && this.site.has_mobile && system.env.HTTP_USER_AGENT.match(/mobile|iPhone|SymbianOS|Opera mini|Opera mobi/i) && !system.env.HTTP_USER_AGENT.match(/ipad|gt-p5100|gt-n7000/i)) {
					this.action="/mobile/index/";
				} else {
					this.action="/index/";
				}
		}
	}
	if (this.site.custom_rewriter) this.site.custom_rewriter(this);
	this.site.rewriter.work(this);
	if (this.action==undefined) {
		this.jsng_response.output=this.prerun_output;
	}
}

/**
 * Method: process_page
 *		Processes page, filling in this.jsng_response.output
 *
 */
LNRR.prototype.process_page=function(server)
{
	if (arr=this.action.match(/^(\/.+)-preview(\d+)(\w*)\.(\w+)/)) {
		this.page_type="preview";
		return this.mkpreview(arr[1],arr[2],arr[3],arr[4]);

	} else if (arr=this.action.match(/^\/admin-(\w+)\/?$/)) {
		this.page_type="admin";
		return this.check_json(this.process_admin_page(arr[1],"index",0));
	
	} else if (arr=this.action.match(/^\/admin-(\w+)-(\w+)\/?$/)) {
		this.page_type="admin";
		return this.check_json(this.process_admin_page(arr[1],arr[2],0));
	
	} else if (arr=this.action.match(/^\/admin_popup-(\w+)-(\w+)\/?$/)) {
		this.page_type="admin";
		return this.check_json(this.process_admin_page(arr[1],arr[2],1));

	} else if (arr=this.action.match(/^\/admin_popup-(\w+)\/?$/)) {
		this.page_type="admin";
		return this.check_json(this.process_admin_page(arr[1],"index",1));

	} else if (this.action=="/admin/") {
		this.page_type="admin";
		return this.check_json(this.process_admin_page("","",0));

	} else if (this.action=="/client-side-views/") {
		this.page_type="client-side-views";
		return this.build_client_side_views();

	} else if (this.action=="/ajaj-auth/") {
		this.fields.ajaj=1;
		if (!this.uid || this.auth_error) {
			if (this.fields.onerror_response) return this.fields.onerror_response;
			this.jsng_response.render_http_error(this,401,"Incorrect username or password");
			return this.jsng_response.output;
		}
		if (this.fields.onsuccess_response) return this.fields.onsuccess_response;
		return JSON.stringify({refresh: 1,auth:1})+"\n\n";
	}
	this.page_type="regular";
	return this.check_json(this.process_regular_page(server));
}

/**
 * Method: check_json
 */
LNRR.prototype.check_json=function(tmp)
{
	if (tmp && tmp.constructor===String && tmp.match(/^\{/)) {
		this.ln_response.response_headers["Content-Type"]="application/json";
	}
	return tmp;
}

/**
 * Method: process_regular_page
 *		Processes page, filling in this.jsng_response.output
 *
 */
LNRR.prototype.process_regular_page=function(server)
{
	var t=rr=this;
	var page=this.site.models.Page.List("get_by_alias",{alias:this.action})[0];
	if (!page) {
		this.jsng_response.render_http_error(this,404,"Page not found");
		return this.jsng_response.output;
	}
	if (this.uid==0 && (page.hide_anon==1 || (page.role_id && !(this.role_ids[page.role_id])))) {
		if (this.site.auth && this.site.auth.prompt_login) {
			this.jsng_response.status_code="403";
			if (this.fields.ajaj) {
				this.ln_response.set_no_cache();
				return JSON.stringify({error_code:"403",error:"Unauthorized"});
			}
			this.pageinfo={cssclass:"loginbody"};
			return this.View("system/login");
		} else {
			this.jsng_response.render_http_error(this,403,"Unauthorized: must be logged in");
		}
		return this.jsng_response.output;
	}
	if (page.hide_reg==1 && this.uid) {
		this.jsng_response.render_http_error(this,403,"Unauthorized: must be logged off");
		return this.jsng_response.output;
	}
	if (page.role_id && !(this.role_ids[page.role_id])) {
		this.jsng_response.render_http_error(this,403,"Unauthorized: no role");
		return this.jsng_response.output;
	}
	if (!page.title) page.title=page.name;
	this.pageinfo=page;

	var needs_preprocess=[];
	var page_blocks=this.site.sql.execute_and_fetch("page_blocks/list_for_page",{page_id: page.id,l10n_id:this.use_l10n_id,medium_id:1});
	var fb_page_blocks;//=this.site.sql.execute_and_fetch("page_blocks/list_for_page",{page_id: page.id,l10n_id:this.fallback_l10n_id,medium_id:1});
	for (var pbn=0,pbs=page_blocks.length;pbn<pbs;pbn++) {
		var pblock=page_blocks[pbn];
		var a=pblock.body;
		if (a=="<p></p>") a=null;
		if (a==null) { // Falling back
			if (!fb_page_blocks) {
				var tmp=this.site.sql.execute_and_fetch("page_blocks/list_for_page",{page_id: page.id,l10n_id:this.fallback_l10n_id,medium_id:1});
				fb_page_blocks={};
				for (var fbn=0;fbn<tmp.length;fbn++) fb_page_blocks[tmp[fbn].place_code]=tmp[fbn];
			}
			var pblock2=fb_page_blocks[pblock.place_code];//t.site.sql.execute_and_fetch_one("page_blocks/get_fallback_for_page",{page_id: page.id,place_code:pblock.place_code,l10n_id:t.fallback_l10n_id,medium_id:1});
			if (pblock2) a=pblock2.body;
			if (a=="<p></p>") a=null;
		}
		var ptc=pblock.place_type_code;
		if (a!=null && a!="" && pblock.preprocess) needs_preprocess.push(pblock.place_code);
		t[pblock.place_code]=a;
	}

	if (page.prerun) {
		var evaltext;
		try {
			var arr=page.prerun.match(/^(\w+)\.(\w+)/);
			if (!arr) arr=[null,page.prerun,t.fields.mode||"index"];
			var config={};
			if (t.fields.mode) arr[2]=t.fields.mode;
//			throw {arr:arr,fields:t.fields};
			if (page.prerun_param) {
				evaltext="t.prerun_output=this.C('"+arr[1]+"','"+arr[2]+"',"+page.prerun_param+",t.fields.ajaj?true:false);";
				eval(evaltext);
			} else {
				evaltext=arr[1]+"."+arr[2];
				t.prerun_output=this.C(arr[1],arr[2],{},t.fields.ajaj?true:false);
			}
		} catch (e) {
			this.site.sql.rollback();
			t.prerun_error=1;
			t.prerun_output="<div style='border: 1px dashed gray;padding: 4px; margin: 4px;'><h1>prerun has thrown an error</h1>";
			t.prerun_output+="<pre>"+this.Dumper(e)+"\n"+evaltext+"</pre></div>";
			if (!this.no_error_notify) this.F("Admin","send_error_notification",e);
//			this.site.functions.send_error_notification(space,this.site.functions.Dumper(e));
		}
		if (this.jsng_response._render_http_error) return t.prerun_output;
	}


	if (this.fields.ajaj) {
		this.ln_response.set_no_cache();
		if (this.prerun_error) {
			this.jsng_response.render_http_error(this,500,"Prerun error",this.prerun_output);
			if (this.fields["is-iframe"]) {
				this.call_function=this.fields["iframe-response"] || "std_response";
				this.output=this.prerun_output=prepare_ajajform_iframe(this.jsng_response.output);
				return this.views.process("system/ajajform_iframe",this);
			} else {
				return this.ln_response.output;
			}
		}
		//if (this.prerun_output.match(/^</)) this.prerun_output=JSON.stringify(this.prerun_output);
		if (this.fields["is-iframe"]) {
			this.call_function=this.fields["iframe-response"] || "std_response";
			this.output=prepare_ajajform_iframe(this.prerun_output);
			return this.views.process("system/ajajform_iframe",this);
		} else {
			return this.prerun_output||this.output;
		}
	}
	for (var pbn=0,pbs=needs_preprocess.length;pbn<pbs;pbn++) {
		t[needs_preprocess[pbn]]=t.views.apply(t[needs_preprocess[pbn]],t);
	}
	if (this.pageinfo.title.match(/\{\{/)) this.pageinfo.title=this.views.apply(this.pageinfo.title,this);
	return this.view('pagetemplates/'+(page.template_code || page.template_id));
}

/**
 * Method: view_apply
 *		
 * Parameters:
 *		tmpl typeof String - Template
 */
LNRR.prototype.view_apply=function(tmpl)
{
	return this.views.apply(tmpl,this);
}

/**
 * Method: view
 *		
 * Parameters:
 *		filename typeof String - file name
 */
LNRR.prototype.view=function(filename)
{
	return this.views.process(filename);
}


/**
 * Method: process_admin_page
 *		
 *
 */
LNRR.prototype.process_admin_page=function(controller,mode,is_popup)
{
	this.ln_response.set_no_cache();
	this.adminpanel={};
	if (!this.uid) {
		this.jsng_response.status_code="403";
		return this.view("system/login");
	}
	if (this.fields.mode) mode=this.fields.mode;
	var config;
//	if (controller!="") throw {controller:controller,mode:mode};
	this.body="";
	if (controller!="") this.body=this.C(controller,mode,config); else this.body=this.View("system/adminpanel/indexpage");
	if (this.fields.ajaj) {
		if (this.fields["is-iframe"]) {
			this.call_function=this.fields["iframe-response"] || "std_response";
			this.output=prepare_ajajform_iframe(this.body);
			return this.views.process("system/ajajform_iframe",this);
		}
		return this.body;
	}
	return this.view(is_popup?"system/adminpanel/popup":"system/adminpanel/body");
}

/**
 * Method: View
 *		Render custom view 
 *
 */
LNRR.prototype.View=function(name)
{
	return this.views.process(name);
}

/**
 * Method: Cview
 *		Render view of given controller
 *
 */
LNRR.prototype.Cview=function()
{
	var c=this._cinfo.config;
	return this.views.process("controllers/"+(c.path||"")+c.name+"/"+(c[this._cinfo.mode+"_view"]||this._cinfo.mode));
}

/**
 * Method: controller_configs_join
 *		Controller caller
 *
 */
LNRR.prototype.controller_configs_join=function(config1,config2)
{
	if (!config1) return config2;
	var config={};
	for (var k in config1) config[k]=config1[k];
	for (var k in config2) if (!(k in config)) config[k]=config2[k];
	config["_joined"]=1;
	return config;
}

/**
 * Method: F
 *		Function caller
 *
 */
LNRR.prototype.F=function(section,name,varargs)
{
	if (!this.site.functions[section]) throw new Error("<b>[No rr.site.functions."+section+"]</b>");
	if (!this.site.functions[section][name]) throw new Error("<b>[No rr.site.functions."+section+"."+name+"()]</b>");

	var args = Array.prototype.slice.call(arguments, 2);
	return this.site.functions[section][name].apply(this,args);
}

LNRR.prototype.F1=LNRR.prototype.F;

/**
 * Method: C
 *		Controller caller
 *
 * Parameters:
 *		controller typeof String		- name of controller to call
 *		mode typeof String				- mode of controller, defaults to 'index'
 *		config1 typeof Object, optional	- parameters of controller
 *		nocatch typeof Boolean			- do not do try{} catch {}
 */
LNRR.prototype.C=function(controller,mode,config1,nocatch,nocheck)
{
/**

		var sid=this.F("Cache","gen_sid","_catalog_categories_no_root",[["roles","me2"]]);
		var value=this.F("Cache","get",sid);
		if (value) return value;
		value=this.CC("_catalog_categories_no_root1",config);
		this.F("Cache","set",sid,value);
		return value;
*/
	var sid;
	var d1=new Date();
	var c=this.site.controllers[controller];
	if (!c) {
		this.cname=controller;
		this.cnames=[];
		for (var k in this.site.controllers) this.cnames.push({name:k});
		return this.view("system/errors/controller_missing");
	}
	if (!nocheck && c._config.role_code && !this.roles[c._config.role_code]) return "Access denied";
	if (!c[mode]) {
		this.cname=controller;
		this.cmode=mode;
		return this.view("system/errors/controller_mode_missing");
	}
	if (c._config.cache && c._config.cache[mode]) {
		sid=this.site.functions.Cache.gen_sid.call(this,controller+"."+mode,c._config.cache[mode]);
		var tmpret=this.site.functions.Cache.get.call(this,sid);
		if (tmpret) return tmpret;
	}
	var config;
	if (config1 && config1["_joined"]) config=config1; else config=this.controller_configs_join(config1,c._config);
	var cinfo=this._cinfo;
	this._cinfo={controller:controller,mode:mode,config:config};
	var r;
	if (nocatch) {
		r=c[mode].call(this,config);
		this._cinfo=cinfo;
		if (sid) this.site.functions.Cache.set.call(this,sid,r);
		return r;
	}
	try {
		r=c[mode].call(this,config);
	} catch(e) {
		r="<pre>"+this.SafeDumper(e)+"</pre>";
		this.site.sql.rollback();
		this.F("Admin","send_error_notification",e);
	}
	this._cinfo=cinfo;
	if (sid) this.site.functions.Cache.set.call(this,sid,r);
	if (this.timed_run) this.timed_run.add(controller+"."+mode,d1);
	return r;
}

/**
 * Method: CC
 *		Same controller caller
 *
 */
LNRR.prototype.CC=function(mode,config)
{
	return this.site.controllers[this._cinfo.controller][mode].call(this,config);
}

/**
 * Method: M
 *		Models caller
 *
 */
LNRR.prototype.M=function()
{
	return this.site.modeller(this,config);
}

/**
 * Method: mkpreview
 */
LNRR.prototype.mkpreview=function(filehead,type,typemo,fileext)
{
	var ret=this.F("Files","mkpreview",filehead,type,typemo,fileext);
	switch (ret) {
		case undefined:
			break;
		case "not found":
			this.jsng_response.render_http_error(this,404,"LNRR.mkpreview() - File not found");
			return this.jsng_response.output;
			break;
		default:
			this.jsng_response.render_http_error(this,500,"LNRR.mkpreview() - Error making preview",this.Dumper({error:ret}));
			return this.jsng_response.output;
			break;
	}
	try {
		var f=new fs.File(this.site.paths.html+filehead+"-preview"+type+typemo+"."+fileext);
		f.open("r");
		ret=f.read();
		f.close();
	} catch (e) {
		this.jsng_response.render_http_error(this,500,"Error making preview",this.Dumper({error:e}));
		return this.jsng_response.output;
	}
	this.res.status(200);
	this.jsng_response.response_headers["Content-Type"]=this.F("Files","guess_mime",fileext);
	this.res.header(this.jsng_response.response_headers);
	this.res.write(ret);
	this.jsng_response.silent=1;
	return "";
}

/**
 * Method: build_client_side_views
 */
LNRR.prototype.build_client_side_views=function()
{
	//return this.views.client_side(this,this.site.paths.views+this.fields.folder.replace(/[^a-zA-Z0-9_]+/g,""));
	if (!this.fields.folder) return this.ln_response.render_http_error(this,404,"fields argument is mandatory");
	var r=this.views.client_side(this,this.fields.folder.replace(/[^a-zA-Z0-9_\/]+/g,""));
	this.jsng_response.response_headers["Content-Type"]="text/javascript";
	return r;
}


exports.LNRR=LNRR;

